package com.fenghuajueli.libbasecoreui.upload.pangrowth

import android.app.Application
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.webkit.WebSettings
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.blankj.utilcode.util.DeviceUtils
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.NetworkUtils
import com.fenghuajueli.lib_net.LoggingInterceptor
import com.fenghuajueli.libbasecoreui.upload.UploadService
import com.fenghuajueli.libbasecoreui.utils.MmkvUtils
import com.umeng.commonsdk.UMConfigure
import com.umeng.commonsdk.listener.OnGetOaidListener
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.security.MessageDigest
import java.util.*
import java.util.concurrent.TimeUnit


class PangrowthUtils {

    /**
     * 回调地址
     * 运营给的是这个格式
     * https://www.csjplatform.com/growth_dispatcher/api/attribution_callback_self_built/f7cba651-471b-c46b-0fce-f30de94399bd/android?pg_site_id=5356665&signature=${请用相关方式生成}
     * 这里先把android?pg_site_id=5356665&signature=${请用相关方式生成}去掉，签名密钥秘钥后自动加上
     */
    private var callBackUrl = ""

    /**
     * 在回调地址里拆出来的pg_site_id
     */
    private var pgSiteId = ""

    /**
     * 签名密钥
     * 运营给的
     */
    private var secretKey = ""

    /**
     * 广告账户id
     * 运营给的
     */
    private var adAccountId: String? = ""

    /**
     * 广告计划id
     * 运营给的
     */
    private var campaignId: String? = ""

    /**
     * 广告计划名称
     * 运营给的
     */
    private var campaignName: String? = ""


    private var oaid: String? = ""
    private var uniqueId: String? = ""
    private var androidId: String? = ""
    private var macAddress: String? = ""
    private var ipAddress: String? = ""
    private var userAgent: String? = ""
    private val FIRST_LAUNCH = "FIRST_LAUNCH"

    private lateinit var uploadService: UploadService

    companion object {
        @JvmStatic
        val instance: PangrowthUtils by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            PangrowthUtils()
        }
    }

    init {
        initUploadLocalService()
    }

    /**
     * 获取OAID
     *
     * @param application
     * @param onGetOaidListener
     */
    fun initOaidAction(application: Application, onGetOaidListener: OnGetOaidListener?) {
        try {
            UMConfigure.getOaid(application) {
                oaid = it
                onGetOaidListener?.onGetOaid(it)
            }
        } catch (e: Exception) {
            onGetOaidListener?.onGetOaid("")
            e.printStackTrace()
        }
    }

    /**
     * 初始化参数
     *
     * @param callBackUrl 必填：回调地址
     * 运营给的是这个格式 https://www.csjplatform.com/growth_dispatcher/api/attribution_callback_self_built/f7cba651-471b-c46b-0fce-f30de94399bd/android?pg_site_id=5356665&signature=${请用相关方式生成}
     * 这里需要把pg_site_id=5356665&signature=${请用相关方式生成}去掉
     *
     * @param pgSiteId 必填：在回调地址里拆出来的pg_site_id
     * @param secretKey 必填：运营给的签名密钥
     * @param adAccountId 运营给的广告账户id
     * @param campaignId 运营给的广告计划id
     * @param campaignName 运营给的广告计划名称
     */
    fun initConfig(callBackUrl: String, pgSiteId: String, secretKey: String, adAccountId: String? = "", campaignId: String? = "", campaignName: String? = "") {
        this.callBackUrl = callBackUrl
        this.pgSiteId = pgSiteId
        this.secretKey = secretKey
        this.adAccountId = adAccountId
        this.campaignId = campaignId
        this.campaignName = campaignName
    }

    /**
     * 获取OAID
     * 需要放在子线程
     * @param application
     */
    private suspend fun initDeviceId(application: Application) {
        if (oaid.isNullOrEmpty()) {
            oaid = application.getOaid().first()
        }
        if (uniqueId.isNullOrEmpty()) {
            uniqueId = DeviceUtils.getUniqueDeviceId()
        }
        if (androidId.isNullOrEmpty()) {
            androidId = DeviceUtils.getAndroidID()
        }
        if (macAddress.isNullOrEmpty()) {
            macAddress = DeviceUtils.getMacAddress()
        }
        if (ipAddress.isNullOrEmpty()) {
            ipAddress = NetworkUtils.getIPAddress(true)
        }
        if (userAgent.isNullOrEmpty()) {
            userAgent = getUserAgent(application)
        }
    }

    private fun Application.getOaid() = callbackFlow<String> {
        UMConfigure.getOaid(this@getOaid) {
            trySend(it)
            channel.close()
        }
        awaitClose { }
    }

    /**
     * 上传设备安装时间
     */
    fun openAction(lifecycleOwner: LifecycleOwner, application: Application) {
        if (callBackUrl.isEmpty()) {
            throw NullPointerException("回调地址参数为空,请调用initConfig()初始化参数")
        }
        if (callBackUrl.contains("pg_site_id") || callBackUrl.contains("signature")) {
            throw IllegalArgumentException("回调地址参数错误,pg_site_id=5356665&signature\\\${请用相关方式生成}去掉")
        }
        if (secretKey.isEmpty()) {
            throw NullPointerException("签名密钥参数为空,请调用initConfig()初始化参数")
        }
        lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
            runCatching {
                if (checkIsFirstInstall(application)) {
                    uploadActiveData(application)
                    MmkvUtils.get(FIRST_LAUNCH, false)
                }
            }
        }
    }

    private fun checkIsFirstInstall(application: Application): Boolean {
        val packageManager = application.packageManager
        val packageInfo = packageManager.getPackageInfo(application.packageName, 0)
        return packageInfo.firstInstallTime == packageInfo.lastUpdateTime && MmkvUtils.get(FIRST_LAUNCH, true)
    }

    private suspend fun uploadActiveData(application: Application) {
        initDeviceId(application)

        val installTime = application.getInstallTime()
        if (installTime == 0L) {
            return
        }

        val contentsMap = hashMapOf<String, String>()
        contentsMap.apply {
            //激活时间,必填
            contentsMap["time_ts"] = "$installTime"
            //oaid,必填
            oaid?.let { contentsMap["oaid"] = it }


            //包名
            contentsMap["package"] = application.packageName

            //自归因平台设备唯一标识
            uniqueId?.let { contentsMap["unique_id"] = it }

            //android_id
            androidId?.let { contentsMap["android_id"] = it }

            //mac地址
            macAddress?.let { contentsMap["mac"] = it }

            //ip地址
            ipAddress?.let { contentsMap["ip"] = it }

            //User-Agent
            userAgent?.let { contentsMap["ua"] = it }


            //商标
            contentsMap["device_brand"] = Build.BRAND
            //机型
            contentsMap["model"] = Build.MODEL
            //系统版本
            contentsMap["os_version"] = Build.PRODUCT
            //系统语言
            contentsMap["language"] = Locale.getDefault().language


            //广告投放平台
            contentsMap["ad_platform"] = "juliangyinqing"
            //广告账户id
            contentsMap["ad_account_id"] = adAccountId ?: ""
            //广告计划ID
            contentsMap["campaign_id"] = campaignId ?: ""
            //广告计划名称
            contentsMap["campaign_name"] = campaignName ?: ""
        }

        val signature = generateSignature(contentsMap)
        val toJson = GsonUtils.toJson(contentsMap)
        val result = uploadService.uploadDataToCsjService(pgSiteId, signature, toJson.toRequestBody())
        LogUtils.d("上传结果: $result")
    }

    private fun getUserAgent(context: Context?): String? {
        var userAgent: String? = null
        try {
            userAgent = WebSettings.getDefaultUserAgent(context)
        } catch (ignored: Throwable) {
        }
        if (userAgent == null) {
            userAgent = System.getProperty("http.agent")
        }
        val sb = StringBuilder()
        if (userAgent != null) {
            var i = 0
            val length = userAgent.length
            while (i < length) {
                val c = userAgent[i]
                if (c <= '\u001f' || c >= '\u007f') {
                    sb.append(String.format("\\u%04x", c.code))
                } else {
                    sb.append(c)
                }
                i++
            }
            userAgent = sb.toString()
        }
        return userAgent
    }

    @Throws(PackageManager.NameNotFoundException::class)
    private fun Application.getInstallTime(): Long {
        var installTime: Long = 0
        try {
            installTime = packageManager.getPackageInfo(packageName, 0).firstInstallTime
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
        return installTime
    }

    /**
     * md5加密
     */
    private fun generateSignature(dataMap: Map<String, String>): String {
        val dataBeforeMD5 = StringBuilder()

        TreeMap(dataMap).forEach { data ->
            if (!data.value.isNullOrEmpty()) {
                dataBeforeMD5
                    .append(data.key)
                    .append("=")
                    .append(data.value)
                    .append("&")
            }
        }

        dataBeforeMD5.append("secretKey=").append(secretKey)
        val digest = MessageDigest.getInstance("MD5").digest(dataBeforeMD5.toString().toByteArray())
        return String(encodeHex(digest))
    }

    private fun encodeHex(data: ByteArray): CharArray {
        val digitsLower = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f')

        val l = data.size
        val out = CharArray(l shl 1)

        var i = 0
        var j = 0
        while (i < l) {
            out[j++] = digitsLower[0xF0 and data[i].toInt() ushr 4]
            out[j++] = digitsLower[0x0F and data[i].toInt()]
            i++
        }
        return out
    }


    private fun initUploadLocalService() {
        val logInterceptor = HttpLoggingInterceptor(LoggingInterceptor())
        logInterceptor.level = HttpLoggingInterceptor.Level.BODY
        val builder = OkHttpClient.Builder()
        val okHttpClient = builder
            .readTimeout(15000, TimeUnit.MILLISECONDS)
            .connectTimeout(15000, TimeUnit.MILLISECONDS)
            .addInterceptor(logInterceptor)
            .build()

        uploadService = Retrofit.Builder()
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(callBackUrl)
            .build().create(UploadService::class.java)
    }
}